// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#ifndef JSON_H_INCLUDED
#define JSON_H_INCLUDED

#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)

// Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities.
#if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER) && _MSC_VER == 1800
#define JSONCPP_NORETURN __declspec(noreturn)
#else
#define JSONCPP_NORETURN [[noreturn]]
#endif
#endif

// Support for '= delete' with template declarations was a late addition
// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
// even though these declare themselves to be c++11 compilers.
#if !defined(JSONCPP_TEMPLATE_DELETE)
#if defined(__clang__) && defined(__apple_build_version__)
#if __apple_build_version__ <= 8000042
#define JSONCPP_TEMPLATE_DELETE
#endif
#elif defined(__clang__)
#if __clang_major__ == 3 && __clang_minor__ <= 8
#define JSONCPP_TEMPLATE_DELETE
#endif
#endif
#if !defined(JSONCPP_TEMPLATE_DELETE)
#define JSONCPP_TEMPLATE_DELETE = delete
#endif
#endif

#include <array>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <vector>

// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251 4275)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)

#pragma pack(push, 8)

/* * \brief JSON (JavaScript Object Notation).
 */
namespace Json {
#if JSON_USE_EXCEPTION
/* * Base class for all exceptions we throw.
 *
 * We use nothing but these internally. Of course, STL can throw others.
 */
class JSON_API Exception : public std::exception {
public:
    Exception(String msg);
    ~Exception() noexcept override;
    char const * what() const noexcept override;

protected:
    String msg_;
};

/* * Exceptions which the user cannot easily avoid.
 *
 * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
 *
 * \remark derived from Json::Exception
 */
class JSON_API RuntimeError : public Exception {
public:
    RuntimeError(String const & msg);
};

/* * Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
 *
 * These are precondition-violations (user bugs) and internal errors (our bugs).
 *
 * \remark derived from Json::Exception
 */
class JSON_API LogicError : public Exception {
public:
    LogicError(String const & msg);
};
#endif

// / used internally
JSONCPP_NORETURN void throwRuntimeError(String const & msg);
// / used internally
JSONCPP_NORETURN void throwLogicError(String const & msg);

/* * \brief Type of the value held by a Value object.
 */
enum ValueType {
    nullValue = 0, // /< 'null' value
    intValue,      // /< signed integer value
    uintValue,     // /< unsigned integer value
    realValue,     // /< double value
    stringValue,   // /< UTF-8 string value
    booleanValue,  // /< bool value
    arrayValue,    // /< array value (ordered list)
    objectValue    // /< object value (collection of name/value pairs).
};

enum CommentPlacement {
    commentBefore = 0,      // /< a comment placed on the line before a value
    commentAfterOnSameLine, // /< a comment just after a value on the same line
    commentAfter,           // /< a comment on the line after a value (only make sense for
    // / root value)
    numberOfCommentPlacement
};

/* * \brief Type of precision for formatting of real values.
 */
enum PrecisionType {
    significantDigits = 0, // /< we set max number of significant digits in string
    decimalPlaces          // /< we set max number of digits after "." in string
};

/* * \brief Lightweight wrapper to tag static string.
 *
 * Value constructor and objectValue member assignment takes advantage of the
 * StaticString and avoid the cost of string duplication when storing the
 * string or the member name.
 *
 * Example of usage:
 * \code
 * Json::Value aValue( StaticString("some text") );
 * Json::Value object;
 * static const StaticString code("code");
 * object[code] = 1234;
 * \endcode
 */
class JSON_API StaticString {
public:
    explicit StaticString(const char *czstring) : c_str_(czstring) {}

    operator const char *() const
    {
        return c_str_;
    }

    const char *c_str() const
    {
        return c_str_;
    }

private:
    const char *c_str_;
};

/* * \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
 *
 * This class is a discriminated union wrapper that can represents a:
 * - signed integer [range: Value::minInt - Value::maxInt]
 * - unsigned integer (range: 0 - Value::maxUInt)
 * - double
 * - UTF-8 string
 * - boolean
 * - 'null'
 * - an ordered list of Value
 * - collection of name/value pairs (javascript object)
 *
 * The type of the held value is represented by a #ValueType and
 * can be obtained using type().
 *
 * Values of an #objectValue or #arrayValue can be accessed using operator[]()
 * methods.
 * Non-const methods will automatically create the a #nullValue element
 * if it does not exist.
 * The sequence of an #arrayValue will be automatically resized and initialized
 * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
 *
 * The get() methods can be used to obtain default value in the case the
 * required element does not exist.
 *
 * It is possible to iterate over the list of member keys of an object using
 * the getMemberNames() method.
 *
 * \note #Value string-length fit in size_t, but keys must be < 2^30.
 * (The reason is an implementation detail.) A #CharReader will raise an
 * exception if a bound is exceeded to avoid security holes in your app,
 * but the Value API does *not* check bounds. That is the responsibility
 * of the caller.
 */
class JSON_API Value {
    friend class ValueIteratorBase;

public:
    using Members = std::vector<String>;
    using iterator = ValueIterator;
    using const_iterator = ValueConstIterator;
    using UInt = Json::UInt;
    using Int = Json::Int;
#if defined(JSON_HAS_INT64)
    using UInt64 = Json::UInt64;
    using Int64 = Json::Int64;
#endif
    // defined(JSON_HAS_INT64)
    using LargestInt = Json::LargestInt;
    using LargestUInt = Json::LargestUInt;
    using ArrayIndex = Json::ArrayIndex;

    // Required for boost integration, e. g. BOOST_TEST
    using value_type = std::string;

#if JSON_USE_NULLREF
    // Binary compatibility kludges, do not use.
    static const Value &null;
    static const Value &nullRef;
#endif

    // null and nullRef are deprecated, use this instead.
    static Value const & nullSingleton();

    // / Minimum signed integer value that can be stored in a Json::Value.
    static constexpr LargestInt minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
    // / Maximum signed integer value that can be stored in a Json::Value.
    static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
    // / Maximum unsigned integer value that can be stored in a Json::Value.
    static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);

    // / Minimum signed int value that can be stored in a Json::Value.
    static constexpr Int minInt = Int(~(UInt(-1) / 2));
    // / Maximum signed int value that can be stored in a Json::Value.
    static constexpr Int maxInt = Int(UInt(-1) / 2);
    // / Maximum unsigned int value that can be stored in a Json::Value.
    static constexpr UInt maxUInt = UInt(-1);

#if defined(JSON_HAS_INT64)
    // / Minimum signed 64 bits int value that can be stored in a Json::Value.
    static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
    // / Maximum signed 64 bits int value that can be stored in a Json::Value.
    static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
    // / Maximum unsigned 64 bits int value that can be stored in a Json::Value.
    static constexpr UInt64 maxUInt64 = UInt64(-1);
#endif
    // defined(JSON_HAS_INT64)
    // / Default precision for real value for string representation.
    static constexpr UInt defaultRealPrecision = 17;
    // The constant is hard-coded because some compiler have trouble
    // converting Value::maxUInt64 to a double correctly (AIX/xlC).
    // Assumes that UInt64 is a 64 bits integer.
    static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
// when using gcc and clang backend compilers.  CZString
// cannot be defined as private.  See issue #486
#ifdef __NVCC__
public:
#else
private:
#endif
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
    class CZString {
    public:
        enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
        CZString(ArrayIndex index);
        CZString(char const * str, unsigned length, DuplicationPolicy allocate);
        CZString(CZString const & other);
        CZString(CZString &&other) noexcept;
        ~CZString();
        CZString &operator = (const CZString &other);
        CZString &operator = (CZString &&other) noexcept;

        bool operator < (CZString const & other) const;
        bool operator == (CZString const & other) const;
        ArrayIndex index() const;
        // const char* c_str() const; ///< \deprecated
        char const * data() const;
        unsigned length() const;
        bool isStaticString() const;

    private:
        void swap(CZString &other);

        struct StringStorage {
            unsigned policy_ : 2;
            unsigned length_ : 30; // 1GB max
        };

        char const * cstr_; // actually, a prefixed string, unless policy is noDup
        union {
            ArrayIndex index_;
            StringStorage storage_;
        };
    };

public:
    typedef std::map<CZString, Value> ObjectValues;
#endif
    // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION

public:
    /* *
     * \brief Create a default Value of the given type.
     *
     * This is a very useful constructor.
     * To create an empty array, pass arrayValue.
     * To create an empty object, pass objectValue.
     * Another Value can then be set to this one by assignment.
     * This is useful since clear() and resize() will not alter types.
     *
     * Examples:
     * \code
     * Json::Value null_value; // null
     * Json::Value arr_value(Json::arrayValue); // []
     * Json::Value obj_value(Json::objectValue); // {}
     * \endcode
     */
    Value(ValueType type = nullValue);
    Value(Int value);
    Value(UInt value);
#if defined(JSON_HAS_INT64)
    Value(Int64 value);
    Value(UInt64 value);
#endif
    // if defined(JSON_HAS_INT64)
    Value(double value);
    Value(const char *value);                  // /< Copy til first 0. (NULL causes to seg-fault.)
    Value(const char *begin, const char *end); // /< Copy all, incl zeroes.
    /* *
     * \brief Constructs a value from a static string.
     *
     * Like other value string constructor but do not duplicate the string for
     * internal storage. The given string must remain alive after the call to
     * this constructor.
     *
     * \note This works only for null-terminated strings. (We cannot change the
     * size of this class, so we have nowhere to store the length, which might be
     * computed later for various operations.)
     *
     * Example of usage:
     * \code
     * static StaticString foo("some text");
     * Json::Value aValue(foo);
     * \endcode
     */
    Value(const StaticString &value);
    Value(const String &value);
    Value(bool value);
    Value(std::nullptr_t ptr) = delete;
    Value(const Value &other);
    Value(Value &&other) noexcept;
    ~Value();

    // / \note Overwrite existing comments. To preserve comments, use
    // / #swapPayload().
    Value &operator = (const Value &other);
    Value &operator = (Value &&other) noexcept;

    // / Swap everything.
    void swap(Value &other);
    // / Swap values but leave comments and source offsets in place.
    void swapPayload(Value &other);

    // / copy everything.
    void copy(const Value &other);
    // / copy values but leave comments and source offsets in place.
    void copyPayload(const Value &other);

    ValueType type() const;

    // / Compare payload only, not comments etc.
    bool operator < (const Value &other) const;
    bool operator <= (const Value &other) const;
    bool operator >= (const Value &other) const;
    bool operator > (const Value &other) const;
    bool operator == (const Value &other) const;
    bool operator != (const Value &other) const;
    int compare(const Value &other) const;

    const char *asCString() const; // /< Embedded zeroes could cause you trouble!
#if JSONCPP_USING_SECURE_MEMORY
    unsigned getCStringLength() const; // Allows you to understand the length of
                                       // the CString
#endif
    String asString() const; // /< Embedded zeroes are possible.
    /* * Get raw char* of string-value.
     * \return false if !string. (Seg-fault if str or end are NULL.)
     */
    bool getString(char const ** begin, char const ** end) const;
    Int asInt() const;
    UInt asUInt() const;
#if defined(JSON_HAS_INT64)
    Int64 asInt64() const;
    UInt64 asUInt64() const;
#endif
    // if defined(JSON_HAS_INT64)
    LargestInt asLargestInt() const;
    LargestUInt asLargestUInt() const;
    float asFloat() const;
    double asDouble() const;
    bool asBool() const;

    bool isNull() const;
    bool isBool() const;
    bool isInt() const;
    bool isInt64() const;
    bool isUInt() const;
    bool isUInt64() const;
    bool isIntegral() const;
    bool isDouble() const;
    bool isNumeric() const;
    bool isString() const;
    bool isArray() const;
    bool isObject() const;

    // / The `as<T>` and `is<T>` member function templates and specializations.
    template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
    template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;

    bool isConvertibleTo(ValueType other) const;

    // / Number of values in array or object
    ArrayIndex size() const;

    // / \brief Return true if empty array, empty object, or null;
    // / otherwise, false.
    bool empty() const;

    // / Return !isNull()
    explicit operator bool() const;

    // / Remove all object members and array elements.
    // / \pre type() is arrayValue, objectValue, or nullValue
    // / \post type() is unchanged
    void clear();

    // / Resize the array to newSize elements.
    // / New elements are initialized to null.
    // / May only be called on nullValue or arrayValue.
    // / \pre type() is arrayValue or nullValue
    // / \post type() is arrayValue
    void resize(ArrayIndex newSize);

    // @{
    // / Access an array element (zero based index). If the array contains less
    // / than index element, then null value are inserted in the array so that
    // / its size is index+1.
    // / (You may need to say 'value[0u]' to get your compiler to distinguish
    // / this from the operator[] which takes a string.)
    Value &operator[](ArrayIndex index);
    Value &operator[](int index);
    // @}

    // @{
    // / Access an array element (zero based index).
    // / (You may need to say 'value[0u]' to get your compiler to distinguish
    // / this from the operator[] which takes a string.)
    const Value &operator[](ArrayIndex index) const;
    const Value &operator[](int index) const;
    // @}

    // / If the array contains at least index+1 elements, returns the element
    // / value, otherwise returns defaultValue.
    Value get(ArrayIndex index, const Value &defaultValue) const;
    // / Return true if index < size().
    bool isValidIndex(ArrayIndex index) const;
    // / \brief Append value to array at the end.
    // /
    // / Equivalent to jsonvalue[jsonvalue.size()] = value;
    Value &append(const Value &value);
    Value &append(Value &&value);

    // / \brief Insert value in array at specific index
    bool insert(ArrayIndex index, const Value &newValue);
    bool insert(ArrayIndex index, Value &&newValue);

    // / Access an object value by name, create a null member if it does not exist.
    // / \note Because of our implementation, keys are limited to 2^30 -1 chars.
    // / Exceeding that will cause an exception.
    Value &operator[](const char *key);
    // / Access an object value by name, returns null if there is no member with
    // / that name.
    const Value &operator[](const char *key) const;
    // / Access an object value by name, create a null member if it does not exist.
    // / \param key may contain embedded nulls.
    Value &operator[](const String &key);
    // / Access an object value by name, returns null if there is no member with
    // / that name.
    // / \param key may contain embedded nulls.
    const Value &operator[](const String &key) const;
    /* * \brief Access an object value by name, create a null member if it does not
     * exist.
     *
     * If the object has no entry for that name, then the member name used to
     * store the new entry is not duplicated.
     * Example of use:
     * \code
     * Json::Value object;
     * static const StaticString code("code");
     * object[code] = 1234;
     * \endcode
     */
    Value &operator[](const StaticString &key);
    // / Return the member named key if it exist, defaultValue otherwise.
    // / \note deep copy
    Value get(const char *key, const Value &defaultValue) const;
    // / Return the member named key if it exist, defaultValue otherwise.
    // / \note deep copy
    // / \note key may contain embedded nulls.
    Value get(const char *begin, const char *end, const Value &defaultValue) const;
    // / Return the member named key if it exist, defaultValue otherwise.
    // / \note deep copy
    // / \param key may contain embedded nulls.
    Value get(const String &key, const Value &defaultValue) const;
    // / Most general and efficient version of isMember()const, get()const,
    // / and operator[]const
    // / \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
    Value const * find(char const * begin, char const * end) const;
    // / Most general and efficient version of object-mutators.
    // / \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
    // / \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
    Value *demand(char const * begin, char const * end);
    // / \brief Remove and return the named member.
    // /
    // / Do nothing if it did not exist.
    // / \pre type() is objectValue or nullValue
    // / \post type() is unchanged
    void removeMember(const char *key);
    // / Same as removeMember(const char*)
    // / \param key may contain embedded nulls.
    void removeMember(const String &key);
    // / Same as removeMember(const char* begin, const char* end, Value* removed),
    // / but 'key' is null-terminated.
    bool removeMember(const char *key, Value *removed);
    /* * \brief Remove the named map member.
     *
     * Update 'removed' iff removed.
     * \param key may contain embedded nulls.
     * \return true iff removed (no exceptions)
     */
    bool removeMember(String const & key, Value *removed);
    // / Same as removeMember(String const& key, Value* removed)
    bool removeMember(const char *begin, const char *end, Value *removed);
    /* * \brief Remove the indexed array element.
     *
     * O(n) expensive operations.
     * Update 'removed' iff removed.
     * \return true if removed (no exceptions)
     */
    bool removeIndex(ArrayIndex index, Value *removed);

    // / Return true if the object has a member named key.
    // / \note 'key' must be null-terminated.
    bool isMember(const char *key) const;
    // / Return true if the object has a member named key.
    // / \param key may contain embedded nulls.
    bool isMember(const String &key) const;
    // / Same as isMember(String const& key)const
    bool isMember(const char *begin, const char *end) const;

    // / \brief Return a list of the member names.
    // /
    // / If null, return an empty list.
    // / \pre type() is objectValue or nullValue
    // / \post if type() was nullValue, it remains nullValue
    Members getMemberNames() const;

    // / \deprecated Always pass len.
    JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
    void setComment(const char *comment, CommentPlacement placement)
    {
        setComment(String(comment, strlen(comment)), placement);
    }
    // / Comments must be //... or /* ... */
    void setComment(const char *comment, size_t len, CommentPlacement placement)
    {
        setComment(String(comment, len), placement);
    }
    // / Comments must be //... or /* ... */
    void setComment(String comment, CommentPlacement placement);
    bool hasComment(CommentPlacement placement) const;
    // / Include delimiters and embedded newlines.
    String getComment(CommentPlacement placement) const;

    String toStyledString() const;

    const_iterator begin() const;
    const_iterator end() const;

    iterator begin();
    iterator end();

    // Accessors for the [start, limit) range of bytes within the JSON text from
    // which this value was parsed, if any.
    void setOffsetStart(ptrdiff_t start);
    void setOffsetLimit(ptrdiff_t limit);
    ptrdiff_t getOffsetStart() const;
    ptrdiff_t getOffsetLimit() const;

private:
    void setType(ValueType v)
    {
        bits_.value_type_ = static_cast<unsigned char>(v);
    }
    bool isAllocated() const
    {
        return bits_.allocated_;
    }
    void setIsAllocated(bool v)
    {
        bits_.allocated_ = v;
    }

    void initBasic(ValueType type, bool allocated = false);
    void dupPayload(const Value &other);
    void releasePayload();
    void dupMeta(const Value &other);

    Value &resolveReference(const char *key);
    Value &resolveReference(const char *key, const char *end);

    // struct MemberNamesTransform
    // {
    //   typedef const char *result_type;
    //   const char *operator()( const CZString &name ) const
    //   {
    //      return name.c_str();
    //   }
    // };

    union ValueHolder {
        LargestInt int_;
        LargestUInt uint_;
        double real_;
        bool bool_;
        char *string_; // if allocated_, ptr to { unsigned, char[] }.
        ObjectValues *map_;
    } value_;

    struct {
        // Really a ValueType, but types should agree for bitfield packing.
        unsigned int value_type_ : 8;
        // Unless allocated_, string_ must be null-terminated.
        unsigned int allocated_ : 1;
    } bits_;

    class Comments {
    public:
        Comments() = default;
        Comments(const Comments &that);
        Comments(Comments &&that) noexcept;
        Comments &operator = (const Comments &that);
        Comments &operator = (Comments &&that) noexcept;
        bool has(CommentPlacement slot) const;
        String get(CommentPlacement slot) const;
        void set(CommentPlacement slot, String comment);

    private:
        using Array = std::array<String, numberOfCommentPlacement>;
        std::unique_ptr<Array> ptr_;
    };
    Comments comments_;

    // [start, limit) byte offsets in the source JSON text from which this Value
    // was extracted.
    ptrdiff_t start_;
    ptrdiff_t limit_;
};

template <> inline bool Value::as<bool>() const
{
    return asBool();
}
template <> inline bool Value::is<bool>() const
{
    return isBool();
}

template <> inline Int Value::as<Int>() const
{
    return asInt();
}
template <> inline bool Value::is<Int>() const
{
    return isInt();
}

template <> inline UInt Value::as<UInt>() const
{
    return asUInt();
}
template <> inline bool Value::is<UInt>() const
{
    return isUInt();
}

#if defined(JSON_HAS_INT64)
template <> inline Int64 Value::as<Int64>() const
{
    return asInt64();
}
template <> inline bool Value::is<Int64>() const
{
    return isInt64();
}

template <> inline UInt64 Value::as<UInt64>() const
{
    return asUInt64();
}
template <> inline bool Value::is<UInt64>() const
{
    return isUInt64();
}
#endif

template <> inline double Value::as<double>() const
{
    return asDouble();
}
template <> inline bool Value::is<double>() const
{
    return isDouble();
}

template <> inline String Value::as<String>() const
{
    return asString();
}
template <> inline bool Value::is<String>() const
{
    return isString();
}

// / These `as` specializations are type conversions, and do not have a
// / corresponding `is`.
template <> inline float Value::as<float>() const
{
    return asFloat();
}
template <> inline const char *Value::as<const char *>() const
{
    return asCString();
}

/* * \brief Experimental and untested: represents an element of the "path" to
 * access a node.
 */
class JSON_API PathArgument {
public:
    friend class Path;

    PathArgument();
    PathArgument(ArrayIndex index);
    PathArgument(const char *key);
    PathArgument(String key);

private:
    enum Kind { kindNone = 0, kindIndex, kindKey };
    String key_;
    ArrayIndex index_{};
    Kind kind_{ kindNone };
};

/* * \brief Experimental and untested: represents a "path" to access a node.
 *
 * Syntax:
 * - "." => root node
 * - ".[n]" => elements at index 'n' of root node (an array value)
 * - ".name" => member named 'name' of root node (an object value)
 * - ".name1.name2.name3"
 * - ".[0][1][2].name1[3]"
 * - ".%" => member name is provided as parameter
 * - ".[%]" => index is provided as parameter
 */
class JSON_API Path {
public:
    Path(const String &path, const PathArgument &a1 = PathArgument(), const PathArgument &a2 = PathArgument(),
        const PathArgument &a3 = PathArgument(), const PathArgument &a4 = PathArgument(),
        const PathArgument &a5 = PathArgument());

    const Value &resolve(const Value &root) const;
    Value resolve(const Value &root, const Value &defaultValue) const;
    // / Creates the "path" to access the specified node and returns a reference on
    // / the node.
    Value &make(Value &root) const;

private:
    using InArgs = std::vector<const PathArgument *>;
    using Args = std::vector<PathArgument>;

    void makePath(const String &path, const InArgs &in);
    void addPathInArg(const String &path, const InArgs &in, InArgs::const_iterator &itInArg, PathArgument::Kind kind);
    static void invalidPath(const String &path, int location);

    Args args_;
};

/* * \brief base class for Value iterators.
 *
 */
class JSON_API ValueIteratorBase {
public:
    using iterator_category = std::bidirectional_iterator_tag;
    using size_t = unsigned int;
    using difference_type = int;
    using SelfType = ValueIteratorBase;

    bool operator == (const SelfType &other) const
    {
        return isEqual(other);
    }

    bool operator != (const SelfType &other) const
    {
        return !isEqual(other);
    }

    difference_type operator - (const SelfType &other) const
    {
        return other.computeDistance(*this);
    }

    // / Return either the index or the member name of the referenced value as a
    // / Value.
    Value key() const;

    // / Return the index of the referenced Value, or -1 if it is not an
    // / arrayValue.
    UInt index() const;

    // / Return the member name of the referenced Value, or "" if it is not an
    // / objectValue.
    // / \note Avoid `c_str()` on result, as embedded zeroes are possible.
    String name() const;

    // / Return the member name of the referenced Value. "" if it is not an
    // / objectValue.
    // / \deprecated This cannot be used for UTF-8 strings, since there can be
    // / embedded nulls.
    JSONCPP_DEPRECATED("Use `key = name();` instead.")
    char const * memberName() const;
    // / Return the member name of the referenced Value, or NULL if it is not an
    // / objectValue.
    // / \note Better version than memberName(). Allows embedded nulls.
    char const * memberName(char const ** end) const;

protected:
    /* ! Internal utility functions to assist with implementing
     * other iterator functions. The const and non-const versions
     * of the "deref" protected methods expose the protected
     * current_ member variable in a way that can often be
     * optimized away by the compiler.
     */
    const Value &deref() const;
    Value &deref();

    void increment();

    void decrement();

    difference_type computeDistance(const SelfType &other) const;

    bool isEqual(const SelfType &other) const;

    void copy(const SelfType &other);

private:
    Value::ObjectValues::iterator current_;
    // Indicates that iterator is for a null value.
    bool isNull_{ true };

public:
    // For some reason, BORLAND needs these at the end, rather
    // than earlier. No idea why.
    ValueIteratorBase();
    explicit ValueIteratorBase(const Value::ObjectValues::iterator &current);
};

/* * \brief const iterator for object and array value.
 *
 */
class JSON_API ValueConstIterator : public ValueIteratorBase {
    friend class Value;

public:
    using value_type = const Value;
    // typedef unsigned int size_t;
    // typedef int difference_type;
    using reference = const Value &;
    using pointer = const Value *;
    using SelfType = ValueConstIterator;

    ValueConstIterator();
    ValueConstIterator(ValueIterator const & other);

private:
    /* ! \internal Use by Value to create an iterator.
     */
    explicit ValueConstIterator(const Value::ObjectValues::iterator &current);

public:
    SelfType &operator = (const ValueIteratorBase &other);

    SelfType operator ++ (int)
    {
        SelfType temp(*this);
        ++*this;
        return temp;
    }

    SelfType operator -- (int)
    {
        SelfType temp(*this);
        --*this;
        return temp;
    }

    SelfType &operator -- ()
    {
        decrement();
        return *this;
    }

    SelfType &operator ++ ()
    {
        increment();
        return *this;
    }

    reference operator*() const
    {
        return deref();
    }

    pointer operator->() const
    {
        return &deref();
    }
};

/* * \brief Iterator for object and array value.
 */
class JSON_API ValueIterator : public ValueIteratorBase {
    friend class Value;

public:
    using value_type = Value;
    using size_t = unsigned int;
    using difference_type = int;
    using reference = Value &;
    using pointer = Value *;
    using SelfType = ValueIterator;

    ValueIterator();
    explicit ValueIterator(const ValueConstIterator &other);
    ValueIterator(const ValueIterator &other);

private:
    /* ! \internal Use by Value to create an iterator.
     */
    explicit ValueIterator(const Value::ObjectValues::iterator &current);

public:
    SelfType &operator = (const SelfType &other);

    SelfType operator ++ (int)
    {
        SelfType temp(*this);
        ++*this;
        return temp;
    }

    SelfType operator -- (int)
    {
        SelfType temp(*this);
        --*this;
        return temp;
    }

    SelfType &operator -- ()
    {
        decrement();
        return *this;
    }

    SelfType &operator ++ ()
    {
        increment();
        return *this;
    }

    /* ! The return value of non-const iterators can be
     * changed, so the these functions are not const
     * because the returned references/pointers can be used
     * to change state of the base class.
     */
    reference operator*() const
    {
        return const_cast<reference>(deref());
    }
    pointer operator->() const
    {
        return const_cast<pointer>(&deref());
    }
};

inline void swap(Value &a, Value &b)
{
    a.swap(b);
}
} // namespace Json

#pragma pack(pop)

#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif
// if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)

#endif
// JSON_H_INCLUDED
